#include "stdafx.h"

#include <algorithm>
#include <iostream>
#include <memory>
#include <boost/thread.hpp>

#include <plog/log.h>
#include <RdcTransportLib/RdcTransport.h>
#include <serialization/serialization.h>
#include "vcCommunication.h"

//void SendToClient(std::vector<char>&)
//{
//    
//}
//
//void RecvFromClient(std::vector<char>& buf, const Header& hdr )
//{
//    //if (hdr.TID_ == 0) // !!!
//    //    ;// we're in *_stub()
//}

//namespace {
    std::auto_ptr<rdc_transport::IVirtChannel>  channel;
    std::vector<char>                           tmp_read_buffer;
    bool                                        is_data_read = false;

    boost::mutex                                io_mutex;
    boost::mutex                                on_read_mutex;
    boost::shared_mutex                         read_buffer_mutex;
    boost::condition_variable_any               is_read_cond;

    HANDLE                                      read_event = NULL;
    HANDLE                                      EventReadON;


    struct WinsockConnectionCallback 
        : public rdc_transport::IServerVirtChannelCallback
    {
        void OnDisconnect()
        {
            ;
        }
        void OnReconnect()
        {
            ;
        }
    };

    struct WinsockReadHandler : public rdc_transport::IReadHandler
    {
        void OnRead(std::vector<char>* pBuffer);
        void OnReadFail(const char* what);
    };

    void WinsockReadHandler::OnRead(std::vector<char>* pBuffer)
    {
        boost::unique_lock<boost::mutex> lock(on_read_mutex);

        try
        {
            {
                //boost::mutex::scoped_lock lock(mutex);
                boost::lock_guard<boost::shared_mutex> lock(read_buffer_mutex);

                tmp_read_buffer.resize (pBuffer->size());
                std::copy (pBuffer->begin(), pBuffer->end(), tmp_read_buffer.begin());

                is_data_read = true;
            }
            is_read_cond.notify_all();

            /*{
                std::ostringstream out_ss;
                out_ss << "Buffer(" << pBuffer->size() << "): ";
                if (pBuffer->size() > 250)
                    out_ss << "size is " << pBuffer->size();
                else {
                    std::ostream_iterator<char> out_string_stream_it(out_ss, "");
                    std::copy(pBuffer->begin(), pBuffer->end(), out_string_stream_it);
                }
                                    
                LOG(plog::info) << out_ss.str().c_str();
            }*/            
            {
                //boost::mutex::scoped_lock lock(mutex);
                boost::unique_lock<boost::shared_mutex> lock(read_buffer_mutex);
                while (is_data_read)
                {
                    is_read_cond.wait(lock);
                }
            }

            LOG(plog::info) << "OnRead";
            
            /*boost::mutex::scoped_lock lock(io_mutex);
            std::cout << "OnRead\n";*/
            
            //::SetEvent (read_event);
			//WaitForSingleObject(EventReadON);
        }
        catch(std::exception& ex)
        {
            LOG(plog::error) <<  ex.what();
        }
    }

    void WinsockReadHandler::OnReadFail(const char* what)
    {
        LOG(plog::error) << "Server OnReadFail: " << what;
    }

    //void packetisaccepted(bool arg)
    //{
        // if (arg)
        //	 SetEvent(EventReadON);
    //}

    void SendToClient (std::vector<char>& buf)
    {
        LOG(plog::info) << "SendToClient";
        
        channel->Write(&buf);
    }

    void RecvFromClient (std::vector<char>& buf, const Header& hdr)
    {
        LOG(plog::info) << "RecvFromClient";
        //::WaitForSingleObject (read_event, INFINITE);

        {
            boost::shared_lock<boost::shared_mutex> lock(read_buffer_mutex);
            while (!is_data_read)
            {
                is_read_cond.wait(lock);
            }
            
            Deserialize deserialize(tmp_read_buffer);
            if (deserialize.get_header() == hdr)
            {
                buf.resize( tmp_read_buffer.size() );
                std::copy (tmp_read_buffer.begin(), tmp_read_buffer.end(), buf.begin());
            
                //::ResetEvent(read_event);
                /*{
                    std::ostringstream out_ss;
                    out_ss << "Buffer(" << buf.size() << "): ";
                    std::ostream_iterator<char> out_string_stream_it(out_ss, "");
                    std::copy(buf.begin(), buf.end(), out_string_stream_it);
                    
                    LOG(plog::info) << out_ss.str().c_str();
                }*/
            }
        }
        {
            boost::unique_lock<boost::shared_mutex> lock(read_buffer_mutex);
            is_data_read = false;
            is_read_cond.notify_one();
        }
        //::ResetEvent(read_event);
    }

    void SendAndRecvFromVirtualChannel (
        std::vector<char>& in_buf, std::vector<char>& out_buf
        )
    {
        SendToClient(in_buf);

        Deserialize deserialize(tmp_read_buffer);
        RecvFromClient(out_buf, deserialize.get_header());
    }

    void ConnectToVirtualChannel ()
    {
        try
        {
            WinsockReadHandler rh;
            WinsockConnectionCallback cc;

            //std::auto_ptr<rdc_transport::IVirtChannel> ch = 
            channel = rdc_transport::CreateServerChannel("WSCKDR", L"WSCKDR",&cc, &rh);
        }
        catch(std::exception& ex)
        {
            LOG(plog::error) << ex.what();
        }
    }
//}
